import { defineComponent, ref } from 'vue'
import { ElForm, ElFormItem, ElRow, ElCol } from 'element-plus'

import Renderer from '@/components/renderer'
import type { FieldListItem } from './types'
import DefaultRenderer from './render'
import props, { rowProps, colProps, formProps } from './props'
import { extractProps } from './utils'

export default defineComponent({
  name: 'EasyForm',
  props,
  setup(props, { attrs, slots, expose }) {
    const cRowProps = extractProps(props, rowProps)
    const cColProps = extractProps(props, colProps)
    const cFormProps = extractProps(props, formProps)

    const renderFormItem = (item: FieldListItem) => {
      const {
        type,
        prop,
        options,
        label,
        rules,
        renderDefault,
        renderLabel,
        renderError,
        ...otherAttrs
      } = item

      const defaultSlots = {
        default: scope => {
          if (renderDefault) {
            return (
              <Renderer
                render={renderDefault}
                params={Object.assign(
                  scope,
                  { item, model: props.formData },
                  { props, otherAttrs }
                )}
              />
            )
          } else {
            return (
              <DefaultRenderer
                type={type}
                item={item}
                formData={props.formData}
                prop={prop}
                options={options}
                {...otherAttrs}
              />
            )
          }
        }
      }
      const labelSlots = renderLabel
        ? {
            label: scope => {
              return (
                <Renderer
                  render={renderLabel}
                  params={Object.assign(scope, {
                    props,
                    otherAttrs
                  })}
                />
              )
            }
          }
        : {}
      const errorSlots = renderError
        ? {
            error: scope => {
              return (
                <template>
                  <Renderer
                    render={renderError}
                    params={Object.assign(scope, {
                      props,
                      otherAttrs
                    })}
                  />
                </template>
              )
            }
          }
        : {}

      const scopedSlots = {
        ...defaultSlots,
        ...labelSlots,
        ...errorSlots
      }

      return (
        <ElCol {...cColProps} {...attrs}>
          <ElFormItem prop={prop} label={label} rules={rules} {...otherAttrs}>
            {scopedSlots}
          </ElFormItem>
        </ElCol>
      )
    }

    const formRef = ref<typeof ElForm | null>(null)
    expose({
      formRef
    })

    return () => (
      <>
        {/* 修复attrs.formOptions可能不是对象的问题 */}
        <ElForm ref={formRef} model={props.formData} {...cFormProps} {...attrs}>
          <ElRow {...cRowProps}>
            {props.fieldList.map((field: FieldListItem) => {
              return renderFormItem(field)
            })}
            {slots.default?.()}
          </ElRow>
        </ElForm>
      </>
    )
  }
})
